function RFW.Bob_DefaultBobstyleInt(p)
	local bobxoffset = FixedInt(FixedMul(p.bob, sin(FixedAngle(leveltime*16*FU))))*FU
	local bobyoffset = FixedInt(FixedMul(p.bob/2, abs(sin(FixedAngle(leveltime*16*FU)))))*FU
	return {bobxoffset, bobyoffset}
end

function RFW.Bob_Bobstyle2Int(p) //quakish
	local bobxoffset = FixedInt(2*sin(FixedAngle(leveltime*2*FU))-FU/2)*FU
	local bobyoffset = FixedInt(FixedMul(p.bob/2, sin(FixedAngle(leveltime*16*FU))))*FU
	return {bobxoffset, bobyoffset}
end

function RFW.Bob_DefaultBobstyle(p)
	local bobxoffset = FixedMul(p.bob, sin(FixedAngle(leveltime*16*FU)))
	local bobyoffset = FixedMul(p.bob/2, abs(sin(FixedAngle(leveltime*16*FU))))
	return {bobxoffset, bobyoffset}
end

function RFW.Bob_Bobstyle2(p) //quakish
	local bobxoffset = 2*sin(FixedAngle(leveltime*2*FU))-FU/2
	local bobyoffset = FixedMul(p.bob/2, sin(FixedAngle(leveltime*16*FU)))
	return {bobxoffset, bobyoffset}
end

local function DeltaFixed(start, enda)
	local diff = (enda - start)
    if diff > 180*FU then
        diff = diff - (360*FU-1) //wrap into [-180, +180]
	elseif diff < -180*FU then
        diff = diff + (360*FU-1) //wrap into [-180, +180]
    end
    return diff
end

//

function RFW.Bob_RampageBobSmallWeaps(p)
	//local bobxoffset = FixedInt(FixedMul(p.bob, sin(FixedAngle(leveltime*16*FU))))*FU
	//local bobyoffset = FixedInt(FixedMul(p.bob/2, abs(sin(FixedAngle(leveltime*16*FU)))))*FU
	//local bobxoffset = FixedMul(p.bob, abs(sin(FixedAngle(((leveltime*16*FU)+(FU*22/7))/2)))*2-FU)
	local bobxoffset = FixedMul(p.bob, sin(FixedAngle(leveltime*8*FU)))
	local bobyoffset = FixedMul(p.bob/2, -abs(sin(FixedAngle(leveltime*8*FU)))+FU)
	local mo = p.mo
	//local delta = DeltaFixed(AngleFixed(p.mo.rbpreangle), AngleFixed(p.mo.angle))
	//local delta2 = DeltaFixed(AngleFixed(p.mo.rbpreangle2), AngleFixed(p.mo.rbpreangle))
	//local delta3 = DeltaFixed(AngleFixed(p.mo.rbpreangle3), AngleFixed(p.mo.rbpreangle2))
	//local delta4 = DeltaFixed(AngleFixed(p.mo.rbpreangle4), AngleFixed(p.mo.rbpreangle3))
	//local delta5 = DeltaFixed(AngleFixed(p.mo.rbpreangle5), AngleFixed(p.mo.rbpreangle4))
	//if delta > 0 then
		bobxoffset = $-(mo.rbob_delt+(mo.rbob_delt2/2)+(mo.rbob_delt3/3)+(mo.rbob_delt4/4)+(mo.rbob_delt5/5)+(mo.rbob_delt6/6)+(mo.rbob_delt7/7)+(mo.rbob_delt8/8)+(mo.rbob_delt9/9))/2
	//else
	//	bobxoffset = AngleFixed(p.mo.preangle + p.mo.angle)
	//end
	if AngleFixed(p.aiming) >= 270*FU then
		bobyoffset = $-abs(AngleFixed(p.aiming)-360*FU)/3
	else
		bobyoffset = $-AngleFixed(p.aiming)/3
	end
	bobyoffset = $-(mo.rbob_aimd+(mo.rbob_aimd2/2)+(mo.rbob_aimd3/3)+(mo.rbob_aimd4/4)+(mo.rbob_aimd5/5)+(mo.rbob_aimd6/6)+(mo.rbob_aimd7/7)+(mo.rbob_aimd8/8)+(mo.rbob_aimd9/9))/3
	return {bobxoffset, bobyoffset}
end

function RFW.Bob_RampageBob(p)
	local bobxoffset
	local bobyoffset
	local mo = p.mo
	//local delta = DeltaFixed(AngleFixed(p.mo.rbpreangle), AngleFixed(p.mo.angle))
	//local delta2 = DeltaFixed(AngleFixed(p.mo.rbpreangle2), AngleFixed(p.mo.rbpreangle))
	//local delta3 = DeltaFixed(AngleFixed(p.mo.rbpreangle3), AngleFixed(p.mo.rbpreangle2))
	//local delta4 = DeltaFixed(AngleFixed(p.mo.rbpreangle4), AngleFixed(p.mo.rbpreangle3))
	//local delta5 = DeltaFixed(AngleFixed(p.mo.rbpreangle5), AngleFixed(p.mo.rbpreangle4))
	//if delta > 0 then
		bobxoffset = -(mo.rbob_delt+(mo.rbob_delt2/2)+(mo.rbob_delt3/3)+(mo.rbob_delt4/4)+(mo.rbob_delt5/5)+(mo.rbob_delt6/6)+(mo.rbob_delt7/7)+(mo.rbob_delt8/8)+(mo.rbob_delt9/9))/2
	//else
	//	bobxoffset = AngleFixed(p.mo.preangle + p.mo.angle)
	//end
	if AngleFixed(p.aiming) >= 270*FU then
		bobyoffset = FixedMul(p.bob/2, sin(FixedAngle(leveltime*16*FU)))-abs(AngleFixed(p.aiming)-360*FU)/3
	else
		bobyoffset = FixedMul(p.bob/2, sin(FixedAngle(leveltime*16*FU)))-AngleFixed(p.aiming)/3
	end
	bobyoffset = $-(mo.rbob_aimd+(mo.rbob_aimd2/2)+(mo.rbob_aimd3/3)+(mo.rbob_aimd4/4)+(mo.rbob_aimd5/5)+(mo.rbob_aimd6/6)+(mo.rbob_aimd7/7)+(mo.rbob_aimd8/8)+(mo.rbob_aimd9/9))/3
	return {bobxoffset, bobyoffset}
end

addHook("PreThinkFrame", function()
	for p in players.iterate do
		if not (p.mo and p.mo.valid) then continue end
		//p.mo.rbpreangle5 = p.mo.rbpreangle4
		//p.rbpreaiming5 = p.rbpreaiming4
		//p.mo.rbpreangle4 = p.mo.rbpreangle3
		//p.rbpreaiming4 = p.rbpreaiming3
		//p.mo.rbpreangle3 = p.mo.rbpreangle2
		//p.rbpreaiming3 = p.rbpreaiming2
		//p.mo.rbpreangle2 = p.mo.rbpreangle
		//p.rbpreaiming2 = p.rbpreaiming
		p.mo.rbob_delt9 = p.mo.rbob_delt8 or 0
		p.mo.rbob_delt8 = p.mo.rbob_delt7 or 0
		p.mo.rbob_delt7 = p.mo.rbob_delt6 or 0
		p.mo.rbob_delt6 = p.mo.rbob_delt5 or 0
		p.mo.rbob_delt5 = p.mo.rbob_delt4 or 0
		p.mo.rbob_delt4 = p.mo.rbob_delt3 or 0
		p.mo.rbob_delt3 = p.mo.rbob_delt2 or 0
		p.mo.rbob_delt2 = p.mo.rbob_delt or 0
		p.mo.rbob_delt = DeltaFixed(AngleFixed(p.mo.rbpreangle or 0), AngleFixed(p.mo.angle))
		p.mo.rbob_aimd9 = p.mo.rbob_aimd8 or 0
		p.mo.rbob_aimd8 = p.mo.rbob_aimd7 or 0
		p.mo.rbob_aimd7 = p.mo.rbob_aimd6 or 0
		p.mo.rbob_aimd6 = p.mo.rbob_aimd5 or 0
		p.mo.rbob_aimd5 = p.mo.rbob_aimd4 or 0
		p.mo.rbob_aimd4 = p.mo.rbob_aimd3 or 0
		p.mo.rbob_aimd3 = p.mo.rbob_aimd2 or 0
		p.mo.rbob_aimd2 = p.mo.rbob_aimd or 0
		p.mo.rbob_aimd = DeltaFixed(AngleFixed(p.rbpreaiming or 0), AngleFixed(p.aiming))
		p.mo.rbpreangle = p.mo.angle
		p.rbpreaiming = p.aiming
	end
end)

RFW.Weapons = { //DO NOT MANUALLY ADD WEAPONS TO THIS TABLE, I WILL FIND YOU AND I WILL KILL YOU IF YOU DO
	[1] = {}, //slot 1, normal slot
	[2] = {}, //slot 2, automatic slot
	[3] = {}, //slot 3, bounce slot
	[4] = {}, //slot 4, scatter slot
	[5] = {}, //slot 5, grenade slot
	[6] = {}, //slot 6, explosion slot
	[7] = {}, //slot 7, rail slot
	[8] = {}, //slot 8, galactic earth shaker megakill death laser slot
	[9] = {}, //slot 9, giga death superkill planet cra- wait wait wait, slot 8 and slot 9???
	[10] = {}, //slot 10 or 0, whatever you wanna call it, insert joke about what slot this is in srb2
} //DO NOT MANUALLY ADD WEAPONS TO THIS TABLE, I WILL FIND YOU AND I WILL KILL YOU IF YOU DO

RFW.Ammoids = {
[1] = {"Bullets", 400},
[2] = {"Shells", 100},
[3] = {"Rockets", 100},
[4] = {"Cells", 600},
[5] = {"Utility", 5},
}

function RFW.AddWeapon(slot, data)
	local constant = 1 + #RFW.Weapons[slot]
	RFW.Weapons[slot][constant] = data
	return constant
end

function RFW.WeaponValid(p)
	if p.spectator then return false end
	if p.playerstate == PST_DEAD then return false end
	if p.slot == nil then return false end
	if p.weapon == nil then return false end
	if p.weaponframe == nil then return false end
	return true
end

function RFW.PlayerHasWeapon(p, slot, weapon)
	local has = false
	for k, v in ipairs(p.weaponslist[slot]) do //iterate through our current slot
		if v == weapon then //if the current key value is our current gun
			has = true
			break
		end
	end
	return has
end

function RFW.GivePlayerWeapon(p, slot, weapon)
	if RFW.PlayerHasWeapon(p, slot, weapon) == true then
		return false //dont give the player a weapon they already have, i havent tested it but seeing as the inventory is just a table of weapon ids that the player owns in order if we didn't do this than most likely we would have duplicate weapons
	end //that being said it would maybe be useful to remove this part than if you're doing a hideous destructor style system. Or not probably, it'd probably just be easier to have one weapon pick up and then have a table for each weapon that has the info for each copy of the weapon. just spit balling here. totally.
	local constant = 1 + #p.weaponslist[slot]
	p.weaponslist[slot][constant] = weapon
	table.sort(p.weaponslist[slot], function(a, b)
		//local ap = (RFW.Weapons[p.slot][a]["Priority"] and RFW.Weapons[p.slot][a]["Priority"]) or 1000
		//local bp =
		return (RFW.Weapons[slot][a]["Priority"] or (1000+a)) < (RFW.Weapons[slot][b]["Priority"] or (1000+b))
	end)
	return true
end

function RFW.NextWeapon(p, switch) //start switching to next weapon
	if switch == nil then
		switch = true
	end
	local dick = 0
	local dick2 = 0
	if p.switchto == nil or p.switchslot == nil then
		dick = p.weapon //store the weapon id
		dick2 = p.slot //and the slot, this saves performance and allows me to not have to write everything twice
	else //and thats because if we're already attempting to switch weapons
		dick = p.switchto //then we store the id of the weapon we're switching to!
		dick2 = p.switchslot //same with slot
	end
	local nextweapon = 0
	local weapon = 0
	local slot = dick2
	if dick2 == nil then //if we don't currently have a weapon
		dick2 = 0
		nextweapon = 1
		for die = 1, 10 do //iterate through the next 9 slots
			local FUCK = dick2 + die //next slot is our slot + 1
			if FUCK > 10 then //if we go over 10 than wrap back around
				FUCK = dick2 + die - 10
			end
			if #p.weaponslist[FUCK] ~= 0 then //if theres anything in this new slots table then logically it will always be the 
				weapon = p.weaponslist[FUCK][1]
				slot = FUCK
				break
			else
				continue
			end
		end
		if nextweapon == 1 and weapon == 0 then
			return false //panic, we don't have any weapons
		end
	else
		for k, v in ipairs(p.weaponslist[dick2]) do //iterate through our current slot
			if nextweapon == 1 then //if our next gun is the one we want then cache the weapon id
				weapon = v
				break
			end
			if v == dick then //if the current key value is our current gun
				nextweapon = 1
				continue
			end
		end
		if weapon == 0 then //if we need to find the next gun but we're out of guns in our current slot then iterate through the next slots //nextweapon == 1 and 
			for die = 1, 9 do //iterate through the next 9 slots
				local FUCK = dick2 + die //next slot is our slot + 1
				if FUCK > 10 then //if we go over 10 than wrap back around
					FUCK = dick2 + die - 10
				end
				if #p.weaponslist[FUCK] ~= 0 then //if theres anything in this new slots table then logically it will always be the 
					weapon = p.weaponslist[FUCK][1]
					slot = FUCK
					break
				else
					continue
				end
			end
		end
		if weapon == 0 then //we STILL don't have a weapon! benson is gonna be so pissed bro. //nextweapon == 1 and 
			if #p.weaponslist[dick2] ~= 1 then //if we have more than one weapon in the slot
				weapon = p.weaponslist[dick2][1] //will always be the first weapon then, if we started from the first weapon of a slot and the length was more than 1 then we would have been done back at the first check
				slot = dick2 //it should still be dick2 anyways but we're just making sure
			else
				switch = false //we shouldn't try to switch to our same weapon again, never switch in this instance.
			end
		end
		//if nextweapon == 0 then //if for some reason we no longer have the gun we're trying to switch from.
			
		//end
	end
	if switch == true then //switch to our new weapon if we should switch
		p.switchto = weapon
		p.switchslot = slot
		if p.slot ~= nil and p.weapon ~= nil then
			p.weaponstate = "Lower"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		else
			p.weapon = weapon
			p.slot = slot
			p.weaponstate = "Raise"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		end
	end
	return slot, weapon //return slot and then weapon id
end

function RFW.PreviousWeapon(p, switch) //start switching to previous weapon
	if switch == nil then
		switch = true
	end
	local dick = 0
	local dick2 = 0
	local v = 0 //fucking stupid bullshit mhdfmmgfhmfgmhfgmhfmd.
	if p.switchto == nil or p.switchslot == nil then
		dick = p.weapon //store the weapon id
		dick2 = p.slot //and the slot, this saves performance and allows me to not have to write everything twice
	else //and thats because if we're already attempting to switch weapons
		dick = p.switchto //then we store the id of the weapon we're switching to!
		dick2 = p.switchslot //same with slot
	end
	local nextweapon = 0
	local weapon = 0
	local slot = dick2
	if dick2 == nil then
		dick2 = 11
		nextweapon = 1
		for die = 1, 10 do //iterate through the next 9 slots
			local FUCK = dick2 - die //previous slot is our slot - 1
			if FUCK < 1 then //if we go below 1 than wrap back around
				FUCK = dick2 - die + 10
			end
			if #p.weaponslist[FUCK] ~= 0 then //if theres anything in this new slots table then logically it will always be the last weapon
				if #p.weaponslist[FUCK] == 1 then
					weapon = p.weaponslist[FUCK][1] //because indexing -1 to a table with a length of 1 returns nil ffs
				else
					weapon = p.weaponslist[FUCK][#p.weaponslist[FUCK]]
				end
				slot = FUCK
				break
			else
				continue
			end
		end
		if nextweapon == 1 and weapon == 0 then
			return false //panic, we don't have any weapons
		end
	else
		for k = #p.weaponslist[dick2], 1, -1 do //iterate through our current slot
			v = p.weaponslist[dick2][k] //theres no reverse ipairs so we hack one together like this
			if nextweapon == 1 then //if our next gun is the one we want then cache the weapon id
				weapon = v
				break
			end
			if v == dick then //if the current key value is our current gun
				nextweapon = 1
				continue
			end
		end
		if weapon == 0 then //if we need to find the next gun but we're out of guns in our current slot then iterate through the next slots
			for die = 1, 9 do //iterate through the next 9 slots
				local FUCK = dick2 - die //previous slot is our slot - 1
				if FUCK < 1 then //if we go below 1 than wrap back around
					FUCK = dick2 - die + 10
				end
				if #p.weaponslist[FUCK] ~= 0 then //if theres anything in this new slots table then logically it will always be the last weapon
					if #p.weaponslist[FUCK] == 1 then
						weapon = p.weaponslist[FUCK][1] //because indexing -1 to a table with a length of 1 returns nil ffs
					else
						weapon = p.weaponslist[FUCK][#p.weaponslist[FUCK]]
					end
					slot = FUCK
					break
				else
					continue
				end
			end
		end
		if weapon == 0 then //we STILL don't have a weapon! benson is gonna be so pissed bro.
			if #p.weaponslist[dick2] ~= 1 then //if we have more than one weapon in the slot
				local cache = #p.weaponslist[dick2] //index -1 doesnt work for some reason lul
				weapon = p.weaponslist[dick2][cache] //will always be the last weapon then, if we started from the last weapon of a slot and the length was more than 1 then we would have been done back at the first check
				slot = dick2 //it should still be dick2 anyways but we're just making sure
			else
				switch = false //we shouldn't try to switch to our same weapon again, never switch in this instance.
			end
		end
	end
	if switch == true then //switch to our new weapon if we should switch
		p.switchto = weapon
		p.switchslot = slot
		if p.slot ~= nil and p.weapon ~= nil then
			p.weaponstate = "Lower"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		else
			p.weapon = weapon
			p.slot = slot
			p.weaponstate = "Raise"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		end
	end
	return slot, weapon //return slot and then weapon id
end

function RFW.SlotWeapon(p, slot, switch) //start switching weapon based on slot
	if switch == nil then
		switch = true
	end
	local dick = 0
	local dick2 = 0
	local v = 0
	if p.switchto == nil or p.switchslot == nil then
		dick = p.weapon //store the weapon id
		dick2 = p.slot //and the slot, this saves performance and allows me to not have to write everything twice
	else //and thats because if we're already attempting to switch weapons
		dick = p.switchto //then we store the id of the weapon we're switching to!
		dick2 = p.switchslot //same with slot
	end
	local nextweapon = 0
	local weapon = 0
	if #p.weaponslist[slot] == 0 then //if our slot is empty or the slot we're trying to switch to only has one weapon and we're already using/attempting to switch to that slot then stop
		return weapon, false
	end
	if dick2 == slot then //if the slot we're checking is the slot we already are using/attempting to switch to then we need to iterate to find the next weapon in the slot
		for k = #p.weaponslist[dick2], 1, -1 do //iterate through our current slot
			v = p.weaponslist[dick2][k] //theres no reverse ipairs so we hack one together like this
			if nextweapon == 1 then //if our next gun is the one we want then cache the weapon id
				weapon = v
				break
			end
			if v == dick then //if the current key value is our current gun
				nextweapon = 1
				continue
			end
		end
		if nextweapon and #p.weaponslist[dick2] <= 1 then
			return weapon, false
		end
	end
	if weapon == 0 then //otherwise, if we're at the end of the slot or the slot we're switching to is different than the slot we're using/attempting to switch to then it should always be the first weapon of the slot.
		local en = #p.weaponslist[slot]
		weapon = p.weaponslist[slot][en] //first weapon of the slot, the weapon we have now should never be this already because of the first and second checks, never 1 sized table and always pick next weapon.
	end
	if switch == true then //switch to our new weapon if we should switch
		p.switchto = weapon
		p.switchslot = slot
		if p.slot ~= nil and p.weapon ~= nil then
			p.weaponstate = "Lower"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		else
			p.weapon = weapon
			p.slot = slot
			p.weaponstate = "Raise"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
		end
	end
	return weapon, true //return weapon id and true to indicate we switched successfully
end

function RFW.TrySelectWeapon(p, slot, constant)
	if not RFW.PlayerHasWeapon(p, slot, constant) then return false end //we don't have the weapon we want to switch to
	if not ((p.weaponstate == "Ready" or RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe].ready == true) or p.weaponstate == "Lower" or p.weaponstate == "Raise") then return false end //we're not in a state that lets us switch
	if (p.weapon == constant) and (p.slot == slot) then return false end //we're already holding this weapon
	p.switchto = constant
	p.switchslot = slot
	p.weaponstate = "Lower"
	p.weaponframe = 1
	p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
end

function RFW.DoWeaponChange(p) //actually do the weapon change
	p.weapon = p.switchto //change weapon
	p.slot = p.switchslot //change slot
	p.weaponstate = "Raise" //always state to raise
	p.weaponframe = 1 //always first frame of raise state
	p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0 //set the duration of the raise state, for if you're a hippie
	p.flashstate = nil //we shouldn't be flashing
	p.flashframe = nil //no frame
	p.fframeduration = nil //no duration
	p.switchto = nil //we just switched, remove the switchto weapon
	p.switchslot = nil //same with slot
end

function RFW.WA_Refire(p)
	if p.weaponstate == "Fire" or p.weaponstate == "Hold" then
		if p.cmd.buttons & BT_ATTACK and RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) then
			p.weaponstate = RFW.Weapons[p.slot][p.weapon]["States"]["Hold"] and "Hold" or "Fire"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			p.refire = true
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		end
	elseif p.weaponstate == "AltFire" or p.weaponstate == "AltHold" then
		if p.cmd.buttons & BT_FIRENORMAL and RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) then
			p.weaponstate = RFW.Weapons[p.slot][p.weapon]["States"]["AltHold"] and "AltHold" or "AltFire"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			p.refire = true
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		end
	else
		if p.cmd.buttons & BT_ATTACK and RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) then //fix this to check if states exist
			p.weaponstate = "Fire"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			p.refire = true
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		end
		if p.cmd.buttons & BT_FIRENORMAL and RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) then //fix this to check if states exist
			p.weaponstate = RFW.Weapons[p.slot][p.weapon]["States"]["AltFire"] and "AltFire" or "Fire" //check that our altfire state exists
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			p.refire = true
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		end
	end
end

function RFW.WA_AmmoCheck(p, id, amount)
	if id == 0 then return true end //ammoless weapon id
	if not RFW.Ammoids[id] then return false end
	if not p.ammolist[id] then return false end
	if p.ammolist[id] < amount then return false end
	return true
end

function RFW.WA_UseAmmo(p, fire, amount) //fire: 0 = ammo, 1 = ammo1, 2 = ammo2.
	if fire == nil then
		fire = 0
	end
	if amount == nil then
		amount = 1
	end
	local atype = (fire == 1) and "AmmoType1" or (fire == 2) and "AmmoType2" or "AmmoType"
	local ammoid = RFW.Weapons[p.slot][p.weapon][atype]
	//if RFW.WA_AmmoCheck(p, ammoid, RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) //not needed because ammo checker at start of firing, if you need to check other ammo types then do them manually
	p.ammolist[ammoid] = max($ - amount, 0)
end

/*local fucknipple = CV_RegisterVar({
	name = "cummy",
	defaultvalue = 17,
	PossibleValue = {MIN = 0, MAX = 200},
	flags = CV_NETVAR,
})*/

function RFW.StupidZBullshit(p) //because srb2 FUCKING SUCKS GRAHH
	if P_MobjFlip(p.mo) == 1 then
		return p.mo.z+(p.mo.height*3/4)
	elseif P_MobjFlip(p.mo) == -1 then
		return p.mo.z+(p.mo.height*17/200) //"why 17/200 rdude??" i have no fucking idea. Its still not even technically fully accurate, just much closer.
	else
		return 0
	end
end

function RFW.Sound(p, radius)
	searchBlockmap("objects", function(ref, object)
		if not (object.flags|MF_ENEMY|MF_BOSS) then return nil end
		if object.info.deaf then return nil end
		if (object.target and object.target.valid) then return nil end
		object.target = ref
	end, p.mo, p.mo.x-radius, p.mo.x+radius, p.mo.y-radius, p.mo.y+radius)
end

function RFW.WA_GotoState(p, state, frame)
	p.weaponstate = state or "Ready"
	p.weaponframe = frame or 1
	p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
	local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
	if yourweapon and yourweapon.action then
		yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
	end
end

function RFW.WA_JumpIfKeyDown(p, key, state, frame)
	if p.cmd.buttons & key then
		RFW.WA_GotoState(p, state, frame)
		return true
	end
	return false
end

function RFW.WA_JumpIfKeyPressed(p, key, state, frame)
	if p.cmd.buttons & key and not (p.lastbuttons & key) then
		RFW.WA_GotoState(p, state, frame)
		return true
	end
	return false
end

function RFW.WA_JumpIfUserdata(p, userdata, value, state, frame, equivalence)
	if equivalence == "~=" and p[userdata] ~= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == ">" and p[userdata] > value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == "<" and p[userdata] < value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == ">=" and p[userdata] >= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == "<=" and p[userdata] <= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif p[userdata] == value then
		RFW.WA_GotoState(p, state, frame)
		return true
	end
	return false
end

function RFW.WA_JumpIfMoUserdata(p, userdata, value, state, frame, equivalence)
	if equivalence == "~=" and p.mo[userdata] ~= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == ">" and p.mo[userdata] > value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == "<" and p.mo[userdata] < value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == ">=" and p.mo[userdata] >= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif equivalence == "<=" and p.mo[userdata] <= value then
		RFW.WA_GotoState(p, state, frame)
		return true
	elseif p.mo[userdata] == value then
		RFW.WA_GotoState(p, state, frame)
		return true
	end
	return false
end

function RFW.WA_OperateUserdata(p, userdata, value, operation, cap)
	if operation == "+" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = min($ + value, cap)
		else
			p[userdata] = $ + value
		end
	elseif operation == "-" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = max($ - value, cap)
		else
			p[userdata] = $ - value
		end
	elseif operation == "*" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = min($ * value, cap)
		else
			p[userdata] = $ * value
		end
	elseif operation == "/" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = max($ / value, cap)
		else
			p[userdata] = $ / value
		end
	elseif operation == "**" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = min(FixedMul($, value), cap)
		else
			p[userdata] = FixedMul($, value)
		end
	elseif operation == "//" then
		if type(p[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p[userdata] = 0
		end
		if cap ~= nil then
			p[userdata] = max(FixedDiv($, value), cap)
		else
			p[userdata] = FixedDiv($, value)
		end
	else
		p[userdata] = value
	end
end

function RFW.WA_OperateMoUserdata(p, userdata, value, operation, cap)
	if operation == "+" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = min($ + value, cap)
		else
			p.mo[userdata] = $ + value
		end
	elseif operation == "-" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = max($ - value, cap)
		else
			p.mo[userdata] = $ - value
		end
	elseif operation == "*" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = min($ * value, cap)
		else
			p.mo[userdata] = $ * value
		end
	elseif operation == "/" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = max($ / value, cap)
		else
			p.mo[userdata] = $ / value
		end
	elseif operation == "**" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = min(FixedMul($, value), cap)
		else
			p.mo[userdata] = FixedMul($, value)
		end
	elseif operation == "//" then
		if type(p.mo[userdata]) ~= "number" then //failsafe to make sure userdata can be added
			p.mo[userdata] = 0
		end
		if cap ~= nil then
			p.mo[userdata] = max(FixedDiv($, value), cap)
		else
			p.mo[userdata] = FixedDiv($, value)
		end
	else
		p.mo[userdata] = value
	end
end

function RFW.WA_BasicHitscan(p, damage, angle, aim, range, step)
	//aim assist start
	local mangle = 0 //set these to zero, if we dont have bullet magnetism then we add 0 to our angle
	local maim = 0 //else if we do these'll be added to our angle to aim towards our target
	if p.aimassist and p.bulletmagnetism and p.mo.lockontarget then
		if RFW.vertassist.value ~= 1 then
			mangle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
		end
		local vector = R_PointToDist2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
		maim = R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector, p.mo.lockontarget.z+p.mo.lockontarget.height/2)
		if RFW.vertassist.value ~= 1 then
			mangle = $ - p.mo.angle //change these to delta so we can add them to our current value
		end
		maim = $ - p.aiming
	end
	//aim assist end
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = (angle or p.mo.angle) + mangle, zang = (aim or p.aiming) + maim, distance = range or 4096*FU, steps = step or 256, tclip = true, lclip = true, ignore = p.mo, callback2 = P_SpawnMobj, larg = MT_SMOKE}
	if not next(targetlist) then return false end
	local target = targetlist[1][4]
	if target.type == MT_PLAYER then
		if CanPlayerHurtPlayer(p, target.player, 0) == true then
			Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			return true
		end
	else
		for i = 1, P_RandomRange(1, 3) do
			RFW.SparkCoordinate(target, targetlist[1][1], targetlist[1][2], targetlist[1][3])
		end
		RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		return true
	end
end

function RFW.WA_Flash(p)
	if RFW.Weapons[p.slot][p.weapon]["States"]["Flash"] then
		p.flashstate = "Flash"
		p.flashframe = 1
		p.fframeduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3]*FU, p.weapon_haste)), 1) or 0
		//P_FlashPal(p, 8, p.fframeduration)
		return true
	end
	return false
end

function RFW.WA_LightningHitscan(p, damage, angle, aim, range, step)
	local mangle = 0 //set these to zero, if we dont have bullet magnetism then we add 0 to our angle
	local maim = 0 //else if we do these'll be added to our angle to aim towards our target
	if p.aimassist and p.bulletmagnetism and p.mo.lockontarget then
		if RFW.vertassist.value ~= 1 then
			mangle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
		end
		local vector = R_PointToDist2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
		maim = R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector, p.mo.lockontarget.z+p.mo.lockontarget.height/2)
		if RFW.vertassist.value ~= 1 then
			mangle = $ - p.mo.angle //change these to delta so we can add them to our current value
		end
		maim = $ - p.aiming
	end
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = (angle or p.mo.angle) + mangle, zang = (aim or p.aiming) + maim, distance = range or 4096*FU, steps = step or 256, tclip = false, lclip = true, ignore = p.mo, callback = RFW.SpawnLightning, arg = p}
	if not next(targetlist) then return false end
	for i = 1, #targetlist do
		local target = targetlist[i][4]
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			end
		else
			RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		end
	end
end

function RFW.WA_SniperHitscan(p, damage, angle, aim, range, step)
	local mangle = 0 //only do horizontal aiming so that headshots can still be hit
	if p.aimassist and p.bulletmagnetism and p.mo.lockontarget and RFW.vertassist.value ~= 1 then
		mangle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
		mangle = $ - p.mo.angle //change these to delta so we can add them to our current value
	end
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = (angle or p.mo.angle) + mangle, zang = aim or p.aiming, distance = range or 4096*FU, steps = step or 256, tclip = false, lclip = true, ignore = p.mo, callback = P_SpawnMobj, arg = MT_SMOKE}
	if not next(targetlist) then return false end
	for i = 1, #targetlist do
		//local headshotheight = targetlist[i][4].type // later
		local target = targetlist[i][4]
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				if targetlist[i][3] >= targetlist[i][4].z + targetlist[i][4].height/2 and targetlist[i][3] <= targetlist[i][4].z + targetlist[i][4].height then
					damage = 200
				end
				Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			end
		else
			RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		end
	end
end

/*function RFW.WA_RailHitscan(p, damage, angle, aim, range, step)
	//maybe lets not bullet magnetize this one lol
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = angle or p.mo.angle, zang = aim or p.aiming, distance = range or 4096*FU, steps = step or 256, tclip = false, lclip = true, ignore = p.mo, callback = RFW.SpawnRailtrail, arg = p}
	if not next(targetlist) then return false end
	for i = 1, #targetlist do
		local target = targetlist[i][4]
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			end
		else
			RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		end
	end
end*/

function RFW.WA_RailHitscan(p, damage, edamage, angle, aim, range, step)
	//maybe lets not bullet magnetize this one lol
	local targetlist = P_IterateRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = angle or p.mo.angle, zang = aim or p.aiming, distance = range or 4096*FU, steps = step or 256, tclip = false, lclip = true, ignore = p.mo, callback = RFW.SpawnRailtrail, arg = {p, angle or p.mo.angle, aim or p.aiming}}
	if not next(targetlist) then return false end
	for i = 1, #targetlist do
		local target = targetlist[i][4]
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				Playerdamage(target, p.mo, p.mo, FixedInt(FixedMul(damage*FU, p.weapon_multiplier)) or 5, 0, true)
			end
		else
			local hx = targetlist[1][1]
			local hy = targetlist[1][2]
			local hz = targetlist[1][3]
			for i = 1, P_RandomRange(20, 30) do
				RFW.SparkCoordinate(target, hx, hy, hz)
			end
			for i = 1, P_RandomRange(10, 15) do
				RFW.Bleed(target)
			end
			RFW.DirectDamageEnemy(target, p.mo, p.mo, FixedInt(FixedMul(edamage*FU, p.weapon_multiplier)) or 5, 0)
		end
	end
end

function RFW.WA_PistolShot(p)
	local angle1 = 0
	local angle2 = 0
	if p.refire then
		angle1 = FixedAngle(P_RandomRange(-FU, FU))
		angle2 = FixedAngle(P_RandomRange(-FU, FU))
	end
	RFW.WA_Flash(p)
	RFW.WA_UseAmmo(p)
	RFW.WA_BasicHitscan(p, P_RandomRange(5, 15), p.mo.angle + angle1, p.aiming + angle2, 4096*FU, 1024)
	S_StartSound(p.mo, sfx_PISTOL)
end

function RFW.WA_SGShot(p)
	RFW.WA_Flash(p)
	RFW.WA_UseAmmo(p)
	for i = 1, 7 do
		RFW.WA_BasicHitscan(p, P_RandomRange(5, 15), p.mo.angle + FixedAngle(P_RandomRange(-3*FU/2, 3*FU/2)), p.aiming + FixedAngle(P_RandomRange(-FU, FU)), 4096*FU, 256)
	end
	S_StartSound(p.mo, sfx_SHOTFR)
end

function RFW.WA_SGRel(p)
	S_StartSound(p.mo, sfx_SHOTPM)
end

function RFW.WA_ChaingunShot(p)
	local angle1 = 0
	local angle2 = 0
	if p.refire then
		angle1 = FixedAngle(P_RandomRange(-2*FU, 2*FU))
		angle2 = FixedAngle(P_RandomRange(-FU, FU))
	end
	RFW.WA_UseAmmo(p)
	//old damage P_RandomRange(5, 15)
	RFW.WA_BasicHitscan(p, P_RandomRange(5, 15), p.mo.angle + angle1, p.aiming + angle2, 8192*FU, 2048)
	S_StartSound(p.mo, sfx_CHAING)
end

function RFW.WA_GrenadeOpen(p)
	S_StartSound(p.mo, sfx_GROPEN)
end

function RFW.WA_GrenadeLoad(p)
	S_StartSound(p.mo, sfx_GRLOAD)
end

function RFW.WA_GrenadeClose(p)
	S_StartSound(p.mo, sfx_GRCLOS)
end

function RFW.WA_GrenadeShot(p)
	RFW.WA_UseAmmo(p)
	local FUCK = RFW.SFPDSfBs(p.mo, MT_SHOTGRENADE, p.mo.angle, p.aiming)
	S_StartSound(p.mo, sfx_cannon)
	P_SetObjectMomZ(FUCK, 6*FU*P_MobjFlip(p.mo), true)
end

function RFW.WA_RocketShot(p)
	RFW.WA_UseAmmo(p)
	RFW.SFPDSfBs(p.mo, MT_RMPROCKET, p.mo.angle, p.aiming)
	S_StartSound(p.mo, sfx_cannon)
end

function RFW.WA_RifleAutoShot(p)
	local angle1 = 0
	local angle2 = 0
	if p.refire then
		angle1 = FixedAngle(P_RandomRange(-2*FU, 2*FU))
		angle2 = FixedAngle(P_RandomRange(-2*FU, 2*FU))
	end
	RFW.WA_UseAmmo(p)
	RFW.WA_BasicHitscan(p, P_RandomRange(15, 20), p.mo.angle + angle1, p.aiming + angle2, 4096*FU, 1024)
	S_StartSound(p.mo, sfx_THOMFR)
	p.refire = true
end

function RFW.WA_KarasawaShot(p)
	RFW.WA_Flash(p)
	RFW.WA_UseAmmo(p)
	local bolt = RFW.SFPDSfBs(p.mo, MT_KARABOLT, p.mo.angle, p.aiming)
	bolt.color = p.secondcolor
	S_StartSound(p.mo, sfx_KARAFR)
end

function RFW.WA_KarasawaFlash(p)
	S_StartSound(p.mo, sfx_KARAID)
	/*if RFW.Weapons[p.slot][p.weapon]["States"]["KFlash"] then
		p.flashstate = "KFlash"
		p.flashframe = 1
		p.fframeduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3]*FU, p.weapon_haste)), 1) or 0
		//P_FlashPal(p, 8, p.fframeduration)
		return true
	end
	return false*/
end

freeslot("sfx_railfr")

function RFW.WA_RailFire(p)
	RFW.WA_UseAmmo(p, 0, 10)
	RFW.WA_RailHitscan(p, 100, 150, p.mo.angle, p.aiming, 8192*FU, 2048)
	S_StartSound(p.mo, sfx_railfr)
end

function RFW.WA_RailCharge(p)
	S_StartSound(p.mo, sfx_RAILCH)
end

function RFW.WA_SniperFire(p)
	RFW.WA_UseAmmo(p)
	RFW.WA_SniperHitscan(p, 75, p.mo.angle, p.aiming, 8192*FU, 2048)
	S_StartSound(p.mo, sfx_SNIPE1)
end

function RFW.WA_SniperBolt1(p)
	S_StartSound(p.mo, sfx_SNIPE2)
end

function RFW.WA_SniperBolt2(p)
	S_StartSound(p.mo, sfx_SNIPE3)
end

function RFW.WA_LightningShot(p)
	if p.mo.eflags & MFE_UNDERWATER then
		RFW.WA_UseAmmo(p)
		Playerdamage(p.mo, nil, nil, 1, DMG_INSTAKILL, true)
		S_StartSound(p.mo, sfx_Q3BOOM)
		return false
	end
	RFW.WA_UseAmmo(p)
	RFW.WA_LightningHitscan(p, 6, p.mo.angle, p.aiming, 512*FU, 32)
	S_StartSound(p.mo, sfx_LIGHTN)
end

function RFW.WA_LightningShot2(p)
	if p.mo.eflags & MFE_UNDERWATER then
		Playerdamage(p.mo, nil, nil, 1, DMG_INSTAKILL, true)
		S_StartSound(p.mo, sfx_Q3BOOM)
		return false
	end
	RFW.WA_LightningHitscan(p, 6, p.mo.angle, p.aiming, 512*FU, 32)
end

function RFW.WA_AxeLunge(p)
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = angle or p.mo.angle, zang = aim or p.aiming, distance = 512*FU, steps = 32, tclip = true, lclip = true, ignore = p.mo}
	if not next(targetlist) then return false end //somebody within 512FU
	local target = targetlist[1][4] //we're about to replace target list so save this variable
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = angle or p.mo.angle, zang = aim or p.aiming, distance = 128*FU, steps = 32, tclip = true, lclip = true, ignore = p.mo}
	if next(targetlist) then return false end //and farther than 128FU
	local distance = R_PointToDist2(p.mo.x, p.mo.y, target.x, target.y)
	local thrust = (distance-128*FU)/4 //3 tics to hit so 3 tic buffer
	p.mo.z = $ + FU*P_MobjFlip(p.mo) //lift off ground by 1FU to prevent dragging on the ground
	P_Thrust(p.mo, p.mo.angle, FixedMul(thrust, cos(p.aiming)))
	p.mo.momz = $ + FixedMul(thrust, sin(p.aiming)) //* P_MobjFlip(p.mo)
end

function RFW.WA_AxeHitscan(p, damage, angle, aim, range, step)
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = angle or p.mo.angle, zang = aim or p.aiming, distance = range or 4096*FU, steps = step or 256, tclip = true, lclip = true, ignore = p.mo, callback2 = P_SpawnMobj, larg = MT_SMOKE, sarg = MT_FLAMEPARTICLE}
	if not next(targetlist) then return false end
	local target = targetlist[1][4]
	if target.type == MT_PLAYER then
		damage = 100
		if CanPlayerHurtPlayer(p, target.player, 0) == true then
			Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			return true
		end
	else
		damage = 25
		RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		return true
	end
end

function RFW.WA_AxeIdle(p)
	S_StartSound(p.mo, sfx_ENRGID)
end

function RFW.WA_AxeHit(p)
	S_StartSound(p.mo, sfx_ENRGFR)
	RFW.WA_AxeHitscan(p, 100, p.mo.angle, p.aiming, 128*FU, 32)
end

function RFW.WA_SniperScope(p)
	p.fovadd = -45*FU
end

function RFW.WA_ScopeRefire(p)
	p.fovadd = -45*FU
	RFW.WA_Refire(p)
end

function RFW.WA_Lower(p)
	p.raiselowercounter = max(min($ + 6, 32), 0)
end

function RFW.WA_Raise(p)
	p.raiselowercounter = max(min($ - 6, 32), 0)
end

function RFW.WA_HarshLanguage(p)
	//mega uber-offending facist finger blast
	S_StartSound(p.mo, sfx_FUCK1+P_RandomRange(0, 3))
end

//

function RFW.WA_CustomBullet(p, ldamage, damage, hspread, vspread, range, refire, pierce, tracer)
	local nhspread = 0
	local nvspread = 0
	if (not refire) or (refire and p.refire) then
		nhspread = FixedAngle(P_RandomRange(-hspread, hspread))
		nvspread = FixedAngle(P_RandomRange(-vspread, vspread))
	end
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = p.mo.angle+nhspread, zang = p.aiming+nvspread, distance = range, steps = FixedInt(range)/16, tclip = (not pierce), lclip = true, ignore = p.mo, callback = (tracer) and P_SpawnMobj or nil, arg = tracer, callback2 = P_SpawnMobj, larg = MT_SMOKE}
	if not next(targetlist) then return false end
	local target = targetlist[1][4]
	damage = FixedInt(FixedMul(P_RandomRange(ldamage, damage)*FU, p.weapon_multiplier))
	if target.type == MT_PLAYER then
		if CanPlayerHurtPlayer(p, target.player, 0) == true then
			Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
			return true
		end
	else
		for i = 1, P_RandomRange(1, 3) do
			RFW.SparkCoordinate(target, targetlist[1][1], targetlist[1][2], targetlist[1][3])
		end
		RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
		return true
	end
end

freeslot("sfx_hedsht")

function RFW.WA_CustomHeadshot(p, bdamage, hdamage, hspread, vspread, range, refire, pierce, tracer)
	local nhspread = 0
	local nvspread = 0
	local damage = bdamage
	if (not refire) or (refire and p.refire) then
		if hspread then
			nhspread = FixedAngle(P_RandomRange(-hspread, hspread))
		end
		if vspread then
			nvspread = FixedAngle(P_RandomRange(-vspread, vspread))
		end
	end
	local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = p.mo.angle+nhspread, zang = p.aiming+nvspread, distance = range, steps = FixedInt(range)/16, tclip = (not pierce), lclip = true, ignore = p.mo, callback = (tracer) and P_SpawnMobj or nil, arg = tracer, callback2 = P_SpawnMobj, larg = MT_SMOKE}
	if not next(targetlist) then return false end
	if not pierce then
		local target = targetlist[1][4]
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				if (P_MobjFlip(target) == 1 and (targetlist[1][3] >= target.z + target.height/2 and targetlist[1][3] <= target.z + target.height)) or (P_MobjFlip(target) == -1 and (targetlist[1][3] >= target.z and targetlist[1][3] <= target.z + target.height/2)) then
					//print("headshot")
					damage = hdamage
					damage = FixedInt(FixedMul($*FU, p.weapon_multiplier))
					S_StartSound(p.mo, sfx_hedsht, p)
				end
				//print("damage")
				Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
				return true
			end
		else
			for i = 1, P_RandomRange(1, 3) do
				RFW.SparkCoordinate(target, targetlist[1][1], targetlist[1][2], targetlist[1][3])
			end
			if target.flags & (MF_ENEMY|MF_BOSS) and (P_MobjFlip(target) == 1 and (targetlist[1][3] >= target.z + target.height/2 and targetlist[1][3] <= target.z + target.height)) or (P_MobjFlip(target) == -1 and (targetlist[1][3] >= target.z and targetlist[1][3] <= target.z + target.height/2)) then
				//print("headshot")
				damage = hdamage
				damage = FixedInt(FixedMul($*FU, p.weapon_multiplier))
				S_StartSound(p.mo, sfx_hedsht, p)
			end
			RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
			return true
		end
	else
		for i = 1, #targetlist do
			local target = targetlist[i][4]
			if target.type == MT_PLAYER then
				if CanPlayerHurtPlayer(p, target.player, 0) == true then
					if (P_MobjFlip(target) == 1 and (targetlist[i][3] >= target.z + target.height/2 and targetlist[i][3] <= target.z + target.height)) or (P_MobjFlip(target) == -1 and (targetlist[i][3] >= target.z and targetlist[i][3] <= target.z + target.height/2)) then
						//print("headshot")
						damage = hdamage
						damage = FixedInt(FixedMul($*FU, p.weapon_multiplier))
						S_StartSound(p.mo, sfx_hedsht, p)
					end
					Playerdamage(target, p.mo, p.mo, damage or 5, 0, true)
				end
			else
				for j = 1, P_RandomRange(1, 3) do
					RFW.SparkCoordinate(target, targetlist[i][1], targetlist[i][2], targetlist[i][3])
				end
				if target.flags & (MF_ENEMY|MF_BOSS) and (P_MobjFlip(target) == 1 and (targetlist[i][3] >= target.z + target.height/2 and targetlist[i][3] <= target.z + target.height)) or (P_MobjFlip(target) == -1 and (targetlist[i][3] >= target.z and targetlist[i][3] <= target.z + target.height/2)) then
					//print("headshot")
					damage = hdamage
					damage = FixedInt(FixedMul($*FU, p.weapon_multiplier))
					S_StartSound(p.mo, sfx_hedsht, p)
				end
				RFW.DirectDamageEnemy(target, p.mo, p.mo, damage or 5, 0)
			end
		end
	end
end

function RFW.WA_CustomSpread(p, ldamage, damage, hspread, vspread, range, amount, pierce, tracer)
	for i = 1, amount do
		local nhspread = FixedAngle(P_RandomRange(-hspread, hspread))
		local nvspread = FixedAngle(P_RandomRange(-vspread, vspread))
		local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = p.mo.angle+nhspread, zang = p.aiming+nvspread, distance = range, steps = FixedInt(range)/16, tclip = (not pierce), lclip = true, ignore = p.mo, callback = (tracer) and P_SpawnMobj or nil, arg = tracer, callback2 = P_SpawnMobj, larg = MT_SMOKE}
		if not next(targetlist) then continue end
		local target = targetlist[1][4]
		local ndamage = FixedInt(FixedMul(P_RandomRange(ldamage, damage)*FU, p.weapon_multiplier))
		//print(ndamage)
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				Playerdamage(target, p.mo, p.mo, ndamage or 5, 0, true)
				continue
			end
		else
			for i = 1, P_RandomRange(1, 3) do
				RFW.SparkCoordinate(target, targetlist[1][1], targetlist[1][2], targetlist[1][3])
			end
			RFW.DirectDamageEnemy(target, p.mo, p.mo, ndamage or 5, 0)
			continue
		end
	end
end

function RFW.WA_ColorSpread(p, ldamage, damage, hspread, vspread, range, amount, pierce, tracer)
	for i = 1, amount do
		local nhspread = FixedAngle(P_RandomRange(-hspread, hspread))
		local nvspread = FixedAngle(P_RandomRange(-vspread, vspread))
		local targetlist = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = RFW.StupidZBullshit(p), ang = p.mo.angle+nhspread, zang = p.aiming+nvspread, distance = range, steps = FixedInt(range)/16, tclip = (not pierce), lclip = true, ignore = p.mo, callback = (tracer) and RFW.SpawnSecondColorTable or nil, arg = {tracer, p}, callback2 = P_SpawnMobj, larg = MT_SMOKE}
		if not next(targetlist) then continue end
		local target = targetlist[1][4]
		local ndamage = FixedInt(FixedMul(P_RandomRange(ldamage, damage)*FU, p.weapon_multiplier))
		if target.type == MT_PLAYER then
			if CanPlayerHurtPlayer(p, target.player, 0) == true then
				Playerdamage(target, p.mo, p.mo, ndamage or 5, 0, true)
				continue
			end
		else
			for i = 1, P_RandomRange(1, 3) do
				RFW.SparkCoordinate(target, targetlist[1][1], targetlist[1][2], targetlist[1][3])
			end
			RFW.DirectDamageEnemy(target, p.mo, p.mo, ndamage or 5, 0)
			continue
		end
	end
end

function RFW.WA_CustomProjectile(p, projectile, spread, refire)
	if spread == nil then
		spread = 0
	end
	local nspread = 0
	if (not refire) or (refire and p.refire) then
		nspread = FixedAngle(P_RandomRange(-spread, spread))
	end
	RFW.SFPDSfBs(p.mo, projectile, p.mo.angle+nspread, p.aiming+nspread)
end

function RFW.WA_CustomProjectileGrenade(p, projectile, spread, refire, thrust)
	if spread == nil then
		spread = 0
	end
	local nspread = 0
	if (not refire) or (refire and p.refire) then
		nspread = FixedAngle(P_RandomRange(-spread, spread))
	end
	local grenade = RFW.SFPDSfBs(p.mo, projectile, p.mo.angle+nspread, p.aiming+nspread)
	P_SetObjectMomZ(grenade, thrust*P_MobjFlip(p.mo), true)
end

function RFW.WA_CustomProjectileGrenade2(p, projectile, spread, refire, thrust)
	if spread == nil then
		spread = 0
	end
	local nspread = 0
	if (not refire) or (refire and p.refire) then
		nspread = FixedAngle(P_RandomRange(-spread, spread))
	end
	local grenade = RFW.SFPDSfBs(p.mo, projectile, p.mo.angle+nspread, p.aiming+nspread)
	grenade.momx = $ + grenade.target.momx
	grenade.momy = $ + grenade.target.momy
	grenade.momz = $ + grenade.target.momz
	P_SetObjectMomZ(grenade, thrust*P_MobjFlip(p.mo), true)
end


function RFW.WA_CustomProjectileSpread(p, projectile, spread, amount)
	for i = 1, amount do
		nspread = FixedAngle(P_RandomRange(-spread, spread))
		RFW.SFPDSfBs(p.mo, projectile, p.mo.angle+nspread, p.aiming+nspread)
	end
end

function RFW.WA_CustomProjectileSecondColor(p, projectile, spread, refire)
	if spread == nil then
		spread = 0
	end
	local nspread = 0
	if (not refire) or (refire and p.refire) then
		nspread = FixedAngle(P_RandomRange(-spread, spread))
	end
	local fart = RFW.SFPDSfBs(p.mo, projectile, p.mo.angle+nspread, p.aiming+nspread)
	if fart then
		fart.color = p.secondcolor
	end
end

function RFW.WA_PlaySound(p, sound)
	S_StartSound(p.mo, sound)
end

/*COM_AddCommand("administerthyfinger", function(p)
	G_SetUsedCheats(false)
	RFW.GivePlayerWeapon(p, 1, RFW.WP_offensive)
end, COM_ADMIN)

COM_AddCommand("andtherewasafingerparty", function(p)
	G_SetUsedCheats(false)
	for i in players.iterate do
		RFW.GivePlayerWeapon(i, 1, RFW.WP_offensive)
	end
end, COM_ADMIN)*/

local function DeltaAngle(start, enda)
	local diff = (enda - start) & ANGLE_MAX //force into unsigned range
    if diff > ANGLE_180 then
        diff = diff - ANGLE_MAX //wrap into [-180, +180]
    end
    return diff
end

function RFW.CapAngle(p, start, cap, nextang)
	local delta = DeltaAngle(start, nextang)
	if abs(delta) <= cap then return nextang end
	if delta > 0 then //we don't need to account for wrap around
		//if nextang > start return start + cap end
		//return start - cap //nextang will always be less than start if we reach here
		return (start + cap) //& ANGLE_MAX
	else //we need to account for wrap around
		//if nextang > start return start - cap end
		//return start + cap //nextang will always be less than start if we reach here
		return (start - cap) //& ANGLE_MAX
	end
end

function RFW.MultiplyAngle(p, start, mul, nextang)
	if nextang == start then return nextang end
	//return (start + (nextang-start) * mul) end
	return (start + FixedMul((nextang-start), mul))
end

addHook("PlayerSpawn", function(p)
	if not (gametyperules & GTR_CAMPAIGN) then
		p.initialized = false
	end
end)

local oldangle1 = 0
local oldangle2 = 0
local oldaim1 = 0
local oldaim2 = 0

addHook("PlayerCmd", function(p, cmd)
	local wepstate = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate]
	if p == consoleplayer then
		if wepstate and wepstate[p.weaponframe].mousemul then
			cmd.angleturn = RFW.MultiplyAngle(p, (oldangle1 or 0)<<16, wepstate[p.weaponframe].mousemul, cmd.angleturn<<16)>>16
			cmd.aiming = RFW.MultiplyAngle(p, (oldaim1 or 0)<<16, wepstate[p.weaponframe].mousemul, cmd.aiming<<16)>>16
		end
		if wepstate and wepstate[p.weaponframe].mousecap then
			cmd.angleturn = RFW.CapAngle(p, (oldangle1 or 0)<<16, wepstate[p.weaponframe].mousecap, cmd.angleturn<<16)>>16
			cmd.aiming = RFW.CapAngle(p, (oldaim1 or 0)<<16, wepstate[p.weaponframe].mousecap, cmd.aiming<<16)>>16
		end
		oldangle1 = cmd.angleturn
		oldaim1 = cmd.aiming
	elseif p == secondaryconsoleplayer then
		if wepstate and wepstate[p.weaponframe].mousemul then
			cmd.angleturn = RFW.MultiplyAngle(p, (oldangle2 or 0)<<16, wepstate[p.weaponframe].mousemul, cmd.angleturn<<16)>>16
			cmd.aiming = RFW.MultiplyAngle(p, (oldaim2 or 0)<<16, wepstate[p.weaponframe].mousemul, cmd.aiming<<16)>>16
		end
		if wepstate and wepstate[p.weaponframe].mousecap then
			cmd.angleturn = RFW.CapAngle(p, (oldangle2 or 0)<<16, wepstate[p.weaponframe].mousecap, cmd.angleturn<<16)>>16
			cmd.aiming = RFW.CapAngle(p, (oldaim2 or 0)<<16, wepstate[p.weaponframe].mousecap, cmd.aiming<<16)>>16
		end
		oldangle2 = cmd.angleturn
		oldaim2 = cmd.aiming
	end
end)

addHook("MobjThinker", function(tpwepsprite)
	if not tpwepsprite.isweaponsprite then return end
	if not (tpwepsprite.target and tpwepsprite.target.valid) then return end
	local p = tpwepsprite.target.player
	if p.playerstate ~= PST_LIVE then return end
	local pmo = tpwepsprite.target
//weapon positioning
	local scale = pmo.scale
	local pwidth = pmo.radius
	tpwepsprite.scale = scale
	tpwepsprite.fuse = 2
	tpwepsprite.angle = pmo.angle
	if P_MobjFlip(pmo) == -1 then
		tpwepsprite.eflags = $|MFE_VERTICALFLIP
		P_MoveOrigin(tpwepsprite, pmo.x+FixedMul(pwidth, cos(pmo.angle-ANGLE_90)), pmo.y+FixedMul(pwidth, sin(pmo.angle-ANGLE_90)),pmo.z-pmo.height/2)
		tpwepsprite.spriteroll = -p.aiming
	else
		tpwepsprite.eflags = $ & ~(MFE_VERTICALFLIP)
		P_MoveOrigin(tpwepsprite, pmo.x+FixedMul(pwidth, cos(pmo.angle-ANGLE_90)), pmo.y+FixedMul(pwidth, sin(pmo.angle-ANGLE_90)),pmo.z+pmo.height/2)
		tpwepsprite.spriteroll = p.aiming
	end
//end positioning
	local currentweapon = (p.slot ~= nil and p.weapon ~= nil) and RFW.Weapons[p.slot][p.weapon] or nil
	if currentweapon and currentweapon["HoldSprite"] then
		tpwepsprite.sprite = currentweapon["HoldSprite"]
		tpwepsprite.frame = currentweapon["HoldFrame"] or 0
		//p.mo.tpwepsprite.alpha = FU
	else
		tpwepsprite.sprite = SPR_NULL
		tpwepsprite.frame = 0
	end
end, MT_GHOST)

addHook("PlayerThink", function(p)
	p.drawangle = p.mo.angle //always face where we're aiming for fairness
	//p.oldangle = p.cmd.angleturn
	//p.oldaiming = p.cmd.aiming
	p.weapondelay = 9
	if p.spectator or p.playerstate == PST_DEAD then
		p.slot = nil
		p.weapon = nil
		p.raiselowercounter = 0
		p.weaponframe = nil
		p.frameduration = nil
		p.flashstate = nil
		p.flashframe = nil
		p.fframeduration = nil
		p.switchto = nil
		p.switchslot = nil
		p.refire = false
		p.initialized = false
		p.weaponslist = {
			[1] = {},
			[2] = {},
			[3] = {},
			[4] = {},
			[5] = {},
			[6] = {},
			[7] = {},
			[8] = {},
			[9] = {},
			[10] = {},
		}
		p.ammolist = {
			[1] = 50,
			[2] = 0,
			[3] = 0,
			[4] = 0,
		}
	end
	if p.raiselowercounter == nil then
		p.raiselowercounter = 0
	end
	if p.raiselowercounter > 32 then
		p.raiselowercounter = 32
	end
	if p.raiselowercounter >= 32 and p.switchto ~= nil then
		RFW.DoWeaponChange(p)
	end
	if p.raiselowercounter <= 0 then
		p.raiselowercounter = 0
		if p.weaponstate == "Raise" then
			p.weaponstate = "Ready"
		end
	end
//
	if p.playerstate == PST_DEAD then
		p.weaponstate = "Ready"
		p.weaponframe = 1
		p.frameduration = 2
		p.flashstate = nil
		p.flashframe = nil
		p.fframeduration = nil
		p.switchto = nil
		p.switchslot = nil
		p.refire = false
		p.weaponslist = {
			[1] = {},
			[2] = {},
			[3] = {},
			[4] = {},
			[5] = {},
			[6] = {},
			[7] = {},
			[8] = {},
			[9] = {},
			[10] = {},
		}
		p.ammolist = {
			[1] = 50,
			[2] = 0,
			[3] = 0,
			[4] = 0,
			[5] = 0,
		}
	end
	if p.cmd.buttons & BT_WEAPONNEXT and not (p.lastbuttons & BT_WEAPONNEXT) and ((p.slot == nil or p.weapon == nil) or (p.weaponstate == "Ready" or RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe].ready == true) or p.weaponstate == "Lower" or p.weaponstate == "Raise") then
		RFW.NextWeapon(p)
	end
	if p.cmd.buttons & BT_WEAPONPREV and not (p.lastbuttons & BT_WEAPONPREV) and ((p.slot == nil or p.weapon == nil) or (p.weaponstate == "Ready" or RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe].ready == true) or p.weaponstate == "Lower" or p.weaponstate == "Raise") then
		RFW.PreviousWeapon(p)
	end
//
	if p.cmd.buttons & BT_WEAPONMASK and not (p.lastbuttons & BT_WEAPONMASK) and ((p.slot == nil or p.weapon == nil) or (p.weaponstate == "Ready" or RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe].ready == true) or p.weaponstate == "Lower" or p.weaponstate == "Raise") then
		RFW.SlotWeapon(p, (p.cmd.buttons & BT_WEAPONMASK))
	end
//
	if not p.initialized and not p.spectator then
		p.weaponslist = {
			[1] = {},
			[2] = {},
			[3] = {},
			[4] = {},
			[5] = {},
			[6] = {},
			[7] = {},
			[8] = {},
			[9] = {},
			[10] = {},
		}
		//RFW.GivePlayerWeapon(p, 1, 1)
		//RFW.GivePlayerWeapon(p, 2, 1)
		//p.weaponstate = "Raise"
		p.slot = nil
		p.weapon = nil
		p.raiselowercounter = 32
		p.weaponframe = 1
		p.frameduration = 2
		p.flashstate = nil
		p.flashframe = nil
		p.fframeduration = nil
		p.switchto = nil
		p.switchslot = nil
		p.ammolist = {
		[1] = 50,
		[2] = 0,
		[3] = 0,
		[4] = 0,
		}
		p.refire = false
		p.initialized = true
	end
	if not (p.mo.tpwepsprite and p.mo.tpwepsprite.valid) then
		local ghost = P_SpawnGhostMobj(p.mo)
		if (ghost and ghost.valid) then
			ghost.color = p.secondcolor
			ghost.isweaponsprite = true
			//ghost.fuse = 2
			ghost.dontdrawforviewmobj = p.mo
			ghost.alpha = FU
			ghost.renderflags = $|RF_PAPERSPRITE
			p.mo.tpwepsprite = ghost
		end
	end
	//if (p == displayplayer and not camera.chase) or (p == secondarydisplayplayer and not camera2.chase) then
	//end
	local wepstate = (p.slot ~= nil and p.weapon ~= nil) and RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate] or nil
	if wepstate and wepstate[p.weaponframe].zoom then
		local zoom = wepstate[p.weaponframe].zoom
		p.fovadd = -zoom*FU
	end
	//if wepstate and wepstate[p.weaponframe].mousemul then
	//	p.mo.angle = RFW.MultiplyAngle(p, p.mo.oldangle or 0, wepstate[p.weaponframe].mousemul, p.mo.angle)
	//	p.aiming = RFW.MultiplyAngle(p, p.oldaiming or 0, wepstate[p.weaponframe].mousemul, p.aiming)
	//end
	//if wepstate and wepstate[p.weaponframe].mousecap then
	//	p.mo.angle = RFW.CapAngle(p, p.mo.oldangle or 0, wepstate[p.weaponframe].mousecap, p.mo.angle)
	//	p.aiming = RFW.CapAngle(p, p.oldaiming or 0, wepstate[p.weaponframe].mousecap, p.aiming)
	//end
	if p.frameduration > 0 then
		p.frameduration = $ - 1
	end
	if p.fframeduration and p.fframeduration > 0 then
		p.fframeduration = $ - 1
	end
	if p.fframeduration == 0 then
		p.flashframe = $ + 1
		local yourflash = RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe]
		if not yourflash then
			p.flashstate = nil
			p.flashframe = nil
			p.fframeduration = nil
		elseif yourflash[1] == "Loop" then
			print("Do not call attempt to call loop in a flash state! Exitting flash now:")
			p.flashstate = nil
			p.flashframe = 0
			p.fframeduration = 0
		elseif yourflash[1] == "Goto" then
			p.flashstate = yourflash[2] or "Flash"
			p.flashframe = 1
			p.fframeduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3]*FU, p.weapon_haste)), 1) or 0
		else
			p.fframeduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.flashstate][p.flashframe][3]*FU, p.weapon_haste)), 1) or 0
		end
		local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
		if yourweapon and yourweapon.action then
			yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
		end
	end
	if (p.weaponstate == "Ready" or (wepstate and wepstate[p.weaponframe].ready == true)) and p.refire == true then
		p.refire = false
	end
	if p.cmd.buttons & BT_ATTACK and (p.weaponstate == "Ready" or (wepstate and wepstate[p.weaponframe].ready == true)) and RFW.WeaponValid(p) and RFW.Weapons[p.slot][p.weapon]["States"]["Fire"] then
		if RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) and p.playerstate ~= PST_DEAD then
			p.weaponstate = "Fire"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		else
			RFW.NextWeapon(p, true)
		end
	end
	if p.cmd.buttons & BT_FIRENORMAL and (p.weaponstate == "Ready" or (wepstate and wepstate[p.weaponframe].ready == true)) and RFW.WeaponValid(p) and RFW.Weapons[p.slot][p.weapon]["States"]["AltFire"] then
		if RFW.WA_AmmoCheck(p, RFW.Weapons[p.slot][p.weapon]["AmmoType"], RFW.Weapons[p.slot][p.weapon]["MinAmmo"]) and p.playerstate ~= PST_DEAD then
			p.weaponstate = "AltFire"
			p.weaponframe = 1
			p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
		else
			RFW.NextWeapon(p, true)
		end
	end
	if p.frameduration == 0 and wepstate then
		for i = 1,256 do //256 max skip frames, after 256 frames emergency exit as we might be caught in a loop.
			p.weaponframe = $ + 1
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if not yourweapon then
				print("FUCKING IDIOT DEVELOPER! USE LOOP OR GOTO TO END WEAPON STATES! (flashes excluded)")
				p.weaponstate = "Ready"
				p.weaponframe = 1
				p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			elseif yourweapon[1] == "Loop" then
				p.weaponframe = 1
				p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			elseif yourweapon[1] == "Goto" then
				p.weaponstate = yourweapon[2] or "Ready"
				p.weaponframe = 1
				p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			else
				p.frameduration = (RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3] ~= 0) and max(FixedInt(FixedDiv(RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe][3]*FU, p.weapon_haste)), 1) or 0
			end
			local yourweapon = RFW.Weapons[p.slot][p.weapon]["States"][p.weaponstate][p.weaponframe]
			if yourweapon and yourweapon.action then
				yourweapon.action(p, yourweapon.arg1 or nil, yourweapon.arg2 or nil, yourweapon.arg3 or nil, yourweapon.arg4 or nil, yourweapon.arg5 or nil, yourweapon.arg6 or nil, yourweapon.arg7 or nil, yourweapon.arg8 or nil, yourweapon.arg9 or nil)
			end
			if p.frameduration > 0 then
				break //stop skipping!!
			else
				continue //frame is 0 tics long, skippppp
			end
		end
	end
end)

addHook("PostThinkFrame", function()
	for p in players.iterate do
		p.mo.oldangle = p.mo.angle
		p.oldaiming = p.aiming
	end
end)

addHook("PreThinkFrame", function()
	for p in players.iterate do
		p.mo.preangle = p.mo.angle
		p.preaiming = p.aiming
	end
end)

hud.add(function(v, p, c)
	local bcenterx = 160 - ((v.width()/(v.dupx() * 2) - 160))
	local bcentery = 100 + ((v.height()/(v.dupy() * 2) - 100))
	local bcenterxFU = bcenterx*FU
	local bcenteryFU = bcentery*FU
	if p.spectator then return end
	local currentweapon = (p.slot ~= nil and p.weapon ~= nil) and RFW.Weapons[p.slot][p.weapon] or nil
	if ((p ~= secondarydisplayplayer and not camera.chase) or (p == secondarydisplayplayer and not camera2.chase)) and (not (p.mapopen and (not p.overlaymap))) and p.pstate ~= PST_DEAD then
		local bobxoffset = 0
		local bobyoffset = 0
		//local currentweapon = RFW.Weapons[p.slot][p.weapon]
		local weapframe = currentweapon and currentweapon["States"][p.weaponstate][p.weaponframe] or nil
		local flashframe = nil
		if p.flashstate and p.flashframe then
			flashframe = currentweapon and currentweapon["States"][p.flashstate][p.flashframe] or nil
		end
		if (p.weaponstate == "Ready" or (currentweapon and currentweapon["States"][p.weaponstate][p.weaponframe].ready == true) or currentweapon["States"][p.weaponstate][p.weaponframe].bob == true) and currentweapon["States"][p.weaponstate][p.weaponframe].bob ~= false then
			/*if RFW.bobstyle == 1 then
				bobxoffset = FixedInt(FixedMul(p.bob, sin(FixedAngle(leveltime*16*FU))))
				bobyoffset = FixedInt(FixedMul(p.bob/2, abs(sin(FixedAngle(leveltime*16*FU)))))
			elseif RFW.bobstyle == 2 then
				bobxoffset = FixedInt(2*sin(FixedAngle(leveltime*2*FU)))
				bobyoffset = FixedInt(FixedMul(p.bob/2, sin(FixedAngle(leveltime*16*FU))))
			else
				bobxoffset = 0
				bobyoffset = 0
			end*/
			local bob = RFW.Weapons[p.slot][p.weapon]["BobFunc"] and RFW.Weapons[p.slot][p.weapon]["BobFunc"](p) or RFW.Bob_DefaultBobstyle(p)
			bobxoffset = bob[1] or 0
			bobyoffset = bob[2] or 0
		end
		if weapframe then //don't render if we don't have a valid frame obviously
			local wepsprite = v.cachePatch(weapframe[1] .. weapframe[2] .. 0)
			v.drawCropped(bcenterxFU-bobxoffset, 200*FU-bobyoffset+(p.raiselowercounter*FU), FU, FU, wepsprite, (weapframe.renderflags) and weapframe.renderflags|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER or (V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER), v.getSectorColormap(p.mo.subsector.sector, p.mo.x, p.mo.y, p.mo.z+(p.mo.height/2), P_GetSectorLightLevelAt(p.mo.subsector.sector, p.mo.x, p.mo.y, p.mo.z+(p.mo.height/2))), 0, 0, wepsprite.width*FU, max(wepsprite.topoffset*FU+bobyoffset, 0))//v.getSectorColormap(p.realmo.subsector.sector, p.realmo.x, p.realmo.y, p.realmo.z+(p.realmo.height/2))
			//brightmap rendering
			if weapframe.brightmap then
				local brightpatch = v.cachePatch(weapframe.brightmap .. weapframe.brightframe .. 0)
				v.drawCropped(bcenterxFU-bobxoffset, 200*FU-bobyoffset+(p.raiselowercounter*FU), FU, FU, brightpatch, (weapframe.brightflags) and weapframe.brightflags|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER or (V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER), v.getColormap(TC_DEFAULT), 0, 0, brightpatch.width*FU, max(brightpatch.topoffset*FU+bobyoffset, 0))
			end
			//colormap rendering
			if weapframe.colormap then
				local secondcolor
				if RFW.restrictsecondcolor.value == 1 and gametyperules & GTR_TEAMS then
					secondcolor = ((p.ctfteam == 1) and skincolor_redteam) or ((p.ctfteam == 2) and skincolor_blueteam) or p.secondcolor
				else
					secondcolor = p.secondcolor
				end
				local colorpatch = v.cachePatch(weapframe.colormap .. weapframe.colorframe .. 0)
				v.drawCropped(bcenterxFU-bobxoffset, 200*FU-bobyoffset+(p.raiselowercounter*FU), FU, FU, colorpatch, (weapframe.colorflags) and weapframe.colorflags|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER or (V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER), v.getColormap(TC_DEFAULT, secondcolor), 0, 0, colorpatch.width*FU, max(colorpatch.topoffset*FU+bobyoffset, 0))
			end
			//weapon flash rendering
			if flashframe then
				local flashpatch = v.cachePatch(flashframe[1] .. flashframe[2] .. 0)
				v.drawCropped(bcenterxFU-bobxoffset, 200*FU-bobyoffset+(p.raiselowercounter*FU), FU, FU, flashpatch, (flashframe.renderflags) and flashframe.renderflags|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER or (V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER), v.getColormap(TC_DEFAULT), 0, 0, flashpatch.width*FU, max(flashpatch.topoffset*FU+bobyoffset, 0))
			end
		end
	end
	/*
	local ammotype = RFW.Weapons[p.slot][p.weapon]["AmmoType"]
	if ammotype ~= 0 then
		v.drawString(bcenterx, 160, tostring(p.ammolist[ammotype]), V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER, "center")
	end
	if p.weaponstate == "Lower" then
		//local weaponname = ((p.switchslot and p.switchto) and (RFW.Weapons[p.switchslot][p.switchto]["Name"] or "Unidentified Weapon"))
		v.drawString(bcenterx, 168, tostring(RFW.Weapons[p.switchslot][p.switchto]["WeaponName"] or "Unidentified Weapon"), V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_50TRANS|V_YELLOWMAP, "small-center")
	elseif p.weaponstate == "Raise" then
		v.drawString(bcenterx, 168, tostring(currentweapon["WeaponName"] or "Unidentified Weapon"), V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_50TRANS|V_YELLOWMAP, "small-center")
	end
	if p.weaponstate ~= "Lower" and p.weaponstate ~= "Raise" and c.chase then
		v.drawString(bcenterx, 168, tostring(currentweapon["WeaponName"] or "Unidentified Weapon"), V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_20TRANS, "small-center")
	end
	*/
end)

/*RFW.SelectWeapon(p, switch)

function RFW.NextWeapon(p, switch)
	local nextweapon = false
	local weaponchose = nil
	for k, v in pairs(p.weaponslist) do
		if nextweapon == true then
			if switch == true then
			RFW
		elseif p.weaponslist[k] == p.currentweapon then
			nextweapon == true
		end
	end
	return
end

function RFW.PrevWeapon(p, switch)
	local nextweapon = false
	
end

function RFW.SlotWeapon(p, switch)
	local nextweapon = false
	
end*/

/*{
	["WeaponName"] = "Handgun",
	["AmmoType"] = 1,
	["AmmoType1"] = 1,
	["AmmoType2"] = 1,
	["MinAmmo"] = 1,
		["States"] = {
			["Ready"] = {
				{PISG, A, 1},
				{Loop}
			},
			
			["Lower"] = {
				{PISG, A, 1, WA_Lower},
				{Loop}
			},
			
			["Raise"] = {
				{PISG, A, 1, WA_Raise},
				{Loop}
			},
			
			["Fire"] = {
				{PISG, B, 3, WA_PistolShot},
				{PISG, C, 2},
				{PISG, D, 2},
				{PISG, E, 2},
				{PISG, D, 1},
				{PISG, C, 1},
				{PISG, B, 1, WA_Refire},
				{Goto, "Ready"}
			},
			
			["Flash"] = { //for easier weapon porting from stuff like zdoom mods, completely optional if not calling the flash state.
				{PISF, A, 3}
				{Stop}
			},
			
			["AltFire"] = {
			},
			
			["AltFlash"] = {
			},
			
			["Hold"] = {
			},
			
			["AltHold"] = {
			},
		}
	}*/